package com.virjar.vscrawler.core.grab.model;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import java.util.List;

public class GrabRequest {
    private String content;
    private Multimap nameValuePairsModel;
    private JSONObject jsonModel;

    public GrabRequest(String content) {
        this.content = content;
    }

    public GrabRequest(JSONObject jsonModel) {
        this.jsonModel = jsonModel;
    }

    public String getString(String name) {
        return getString(name, null);
    }

    public String getString(String name, String defaultValue) {
        initInnerModel();
        if (nameValuePairsModel != null) {
            String ret = nameValuePairsModel.getString(name);
            return ret == null ? defaultValue : ret;
        }
        if (jsonModel != null) {
            String ret = jsonModel.getString(name);
            return ret == null ? defaultValue : ret;
        }
        throw new IllegalStateException("parameter parse failed");
    }

    public int getInt(String name) {
        return getInt(name, 0);
    }

    public int getInt(String name, int defaultValue) {
        initInnerModel();
        if (nameValuePairsModel != null) {
            String value = nameValuePairsModel.getString(name);
            if (value == null || value.trim().isEmpty()) {
                return defaultValue;
            }
            try {
                return Integer.parseInt(value);
            } catch (NumberFormatException e) {
                return defaultValue;
            }
        }
        if (jsonModel != null) {
            try {
                Integer value = jsonModel.getInteger(name);
                if (value == null) {
                    return defaultValue;
                }
                return value;
            } catch (JSONException e) {
                return defaultValue;
            }
        }
        throw new IllegalStateException("parameter parse failed");
    }

    public List<String> getValues(String name) {
        initInnerModel();
        if (nameValuePairsModel != null) {
            return nameValuePairsModel.get(name);
        }
        if (jsonModel != null) {
            Object o = jsonModel.get(name);
            if (o instanceof CharSequence) {
                return Lists.newArrayList(o.toString());
            } else if (o instanceof JSONArray) {
                return Lists.newArrayList(Iterables.filter(Iterables.transform((JSONArray) o, new Function<Object, String>() {
                    @Override
                    public String apply(Object input) {
                        if (input instanceof CharSequence) {
                            return input.toString();
                        }
                        return null;
                    }
                }), new Predicate<String>() {
                    @Override
                    public boolean apply(String input) {
                        return input != null;
                    }
                }));
            }
            return Lists.newArrayList(jsonModel.getString(name));
        }
        throw new IllegalStateException("parameter parse failed");
    }

    public boolean hasParam(String name) {
        initInnerModel();
        if (nameValuePairsModel != null) {
            return nameValuePairsModel.containsKey(name);
        }
        if (jsonModel != null) {
            return jsonModel.containsKey(name);
        }
        throw new IllegalStateException("parameter parse failed");
    }

    public JSONObject getJsonParam() {
        initInnerModel();
        return jsonModel;
    }

    public String jsonPath(String jsonPath) {
        initInnerModel();
        if (jsonModel == null) {
            throw new IllegalStateException("param not  json format");
        }

        Object eval = JSONPath.compile(jsonPath).eval(jsonModel);
        if (eval == null) {
            return null;
        }
        return eval.toString();
    }

    private void initInnerModel() {
        if (nameValuePairsModel != null || jsonModel != null) {
            return;
        }
        synchronized (this) {
            if (nameValuePairsModel != null || jsonModel != null) {
                return;
            }
            String paramContent = content;
            if (paramContent == null) {
                throw new IllegalArgumentException("invoke request can not be empty");
            }
            paramContent = paramContent.trim();
            if (paramContent.startsWith("{")) {
                try {
                    jsonModel = JSONObject.parseObject(paramContent);
                } catch (JSONException e) {
                    //ignore
                }
            }
            if (jsonModel != null) {
                return;
            }
            nameValuePairsModel = Multimap.parseUrlEncoded(paramContent);
        }
    }

    public Multimap getNameValuePairsModel() {
        return nameValuePairsModel;
    }

    public JSONObject getJsonModel() {
        return jsonModel;
    }
}
